home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / intuisup.lha / Intuisup / source.lha / Render / render.c < prev    next >
C/C++ Source or Header  |  1992-09-14  |  29KB  |  958 lines

  1. /* $Revision Header *** Header built automatically - do not edit! ***********
  2.  *
  3.  *    (C) Copyright 1991 by Torsten Jürgeleit
  4.  *
  5.  *    Name .....: render.c
  6.  *    Created ..: Thursday 19-Dec-91 15:14:35
  7.  *    Revision .: 12
  8.  *
  9.  *    Date        Author                 Comment
  10.  *    =========   ====================   ====================
  11.  *    14-Sep-92   Torsten Jürgeleit      open_window(): new flag to prevent
  12.  *                       adding of inner window offsets
  13.  *    28-Jul-92   Torsten Jürgeleit      save window pointer in RenderInfo
  14.  *    28-Jul-92   Torsten Jürgeleit      open_window(): now correct window
  15.  *                       position if RENDER_INFO_FLAG_-
  16.  *                       INNER_WINDOW set
  17.  *    23-Jun-92   Torsten Jürgeleit      close_window() now checks if
  18.  *                                       win->UserPort exists before trying
  19.  *                                       to reply all IntuiMessages
  20.  *    22-Jun-92   Torsten Jürgeleit      after modifying NewWindow struct
  21.  *                                       for inner window mode new window
  22.  *                                       dimension is scaled once again in
  23.  *                                       open_window()
  24.  *    12-May-92   Torsten Jürgeleit      text colors for clear_window()
  25.  *    30-Apr-92   Torsten Jürgeleit      raster for clear_window()
  26.  *    26-Apr-92   Torsten Jürgeleit      special algorithm to calc text 2
  27.  *                                         pen for screens with 1 or 2 planes
  28.  *    22-Mar-92   Torsten Jürgeleit      mungwall hit in create_avail_fonts
  29.  *                                            no CopyMem() instead of 2nd
  30.  *                                            AvailFonts() allowed
  31.  *    18-Mar-92   Torsten Jürgeleit      calc inner window dimension BEFORE
  32.  *                                         centering window in open_window()
  33.  *    06-Jan-92   Torsten Jürgeleit      add font support routines
  34.  *    19-Dec-91   Torsten Jürgeleit      Created this file!
  35.  *
  36.  ****************************************************************************
  37.  *
  38.  *    Routines to get information needed to render ISUP objects and some
  39.  *    window support functions
  40.  *
  41.  * $Revision Header ********************************************************/
  42.  
  43.     /* Includes */
  44.  
  45. #include <exec/types.h>
  46. #include <exec/memory.h>
  47. #include <libraries/diskfont.h>
  48. #include <intuition/intuition.h>
  49. #ifdef AZTEC_C
  50. #include <functions.h>   /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
  51. #endif
  52. #include <libraries/memwatch.h>   /* header file for memory debug link library (Fish 240) - AFTER functions.h */
  53. #include "render.h"
  54.  
  55.     /* Defines */
  56.  
  57. #define RED_SCALE    3    /* amount of RGB values to take in account the different visual impact of those colors */
  58. #define GREEN_SCALE    6
  59. #define BLUE_SCALE    2
  60.  
  61. #define DEFAULT_AVAIL_FONTS_BUFFER_SIZE        1000
  62.  
  63.     /* Externals */
  64.  
  65. IMPORT struct IntuitionBase  *IntuitionBase;
  66.  
  67.     /* Statics */
  68.  
  69. STATIC USHORT image_data_arrow_left[] = {   /* bitmap data for left arrow image */
  70.     0x0780, 0x3e00, 0xf800, 0x3e00, 0x0780, 0x0000, 0x0000, 0x0000,
  71.     0x0000, 0x0000
  72. };
  73. STATIC USHORT image_data_arrow_right[] = {   /* bitmap data for right arrow image */
  74.     0xf000, 0x3e00, 0x0f80, 0x3e00, 0xf000, 0x0000, 0x0000, 0x0000,
  75.     0x0000, 0x0000
  76. };
  77. STATIC USHORT image_data_arrow_up[] = {   /* bitmap data for up arrow image */
  78.     0x0800, 0x1c00, 0x3e00, 0x7700, 0xc180, 0x0000, 0x0000, 0x0000,
  79.     0x0000, 0x0000
  80. };
  81. STATIC USHORT image_data_arrow_down[] = {   /* bitmap data for down arrow image */
  82.     0xc180, 0x7700, 0x3e00, 0x1c00, 0x0800, 0x0000, 0x0000, 0x0000,
  83.     0x0000, 0x0000
  84. };
  85. STATIC USHORT image_data_toggle_knob_unselected[] = {   /* bitmap data for unselected toggle knob image */
  86.     0x1ffc, 0x0000, 0x7000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000,
  87.     0xc000, 0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0x7000, 0x0000,
  88.     0x1000, 0x0000,   /* Plane 0 */
  89.     0x0002, 0x0000, 0x0003, 0x8000, 0x0000, 0xc000,    0x0000, 0xc000,
  90.     0x0000, 0xc000, 0x0000, 0xc000, 0x0000, 0xc000,    0x0003, 0x8000,
  91.     0x0ffe, 0x0000    /* Plane 1 */
  92. };
  93. STATIC USHORT image_data_toggle_knob_selected[] = {   /* bitmap data for selected toggle knob image */
  94.     0x0002, 0x0000, 0x0003, 0x8000, 0x03f0, 0xc000, 0x0ffc, 0xc000,
  95.     0x0ffc, 0xc000, 0x0ffc, 0xc000, 0x03f0, 0xc000, 0x0003, 0x8000,
  96.     0x0ffe, 0x0000,   /* Plane 0 */
  97.     0x1ffc, 0x0000, 0x7000, 0x0000, 0xc3f0, 0x0000,    0xcffc, 0x0000,
  98.     0xcffc, 0x0000, 0xcffc, 0x0000, 0xc3f0, 0x0000,    0x7000, 0x0000,
  99.     0x1000, 0x0000    /* Plane 1 */
  100. };
  101. STATIC USHORT image_data_toggle_check_selected[] = {   /* bitmap data for selected toggle checkmark image */
  102.     0x0038, 0x0060, 0x00c0, 0xe180, 0x7300, 0x3e00, 0x1c00
  103. };
  104. STATIC USHORT image_data_cycle[] = {   /* bitmap data for cycle image */
  105.     0x7f01, 0xc181, 0xc181, 0xc7e1, 0xc3c1, 0xc181, 0xc001,    0xc181,
  106.     0x7f01,   /* Plane 0 */
  107.     0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002,
  108.     0x0002    /* Plane 1 */
  109. };
  110. STATIC USHORT image_data_count_left[] = {   /* bitmap data for left count image */
  111.     0x0700, 0x3f00, 0xff00, 0x3f00, 0x0700
  112. };
  113. STATIC USHORT image_data_count_right[] = {   /* bitmap data for right count image */
  114.     0xe000, 0xfc00, 0xff00, 0xfc00, 0xe000
  115. };
  116. STATIC struct Image  images[] = {
  117.    {        /* left arrow */
  118.     0, 0, IMAGE_ARROW_WIDTH, IMAGE_ARROW_HEIGHT, IMAGE_ARROW_DEPTH,
  119.     &image_data_arrow_left[0], 0, 0, NULL
  120.    }, {        /* right arrow */
  121.     0, 0, IMAGE_ARROW_WIDTH, IMAGE_ARROW_HEIGHT, IMAGE_ARROW_DEPTH,
  122.     &image_data_arrow_right[0], 0, 0, NULL
  123.    }, {        /* up arrow */
  124.     0, 0, IMAGE_ARROW_WIDTH, IMAGE_ARROW_HEIGHT, IMAGE_ARROW_DEPTH,
  125.     &image_data_arrow_up[0], 0, 0, NULL
  126.    }, {        /* down arrow */
  127.     0, 0, IMAGE_ARROW_WIDTH, IMAGE_ARROW_HEIGHT, IMAGE_ARROW_DEPTH,
  128.     &image_data_arrow_down[0], 0, 0, NULL
  129.    }, {        /* toggle select knob unselected */
  130.     0, 0, IMAGE_KNOB_WIDTH, IMAGE_KNOB_HEIGHT, IMAGE_KNOB_DEPTH,
  131.     &image_data_toggle_knob_unselected[0], 0, 0, NULL
  132.    }, {        /* toggle select knob selected */
  133.     0, 0, IMAGE_KNOB_WIDTH, IMAGE_KNOB_HEIGHT, IMAGE_KNOB_DEPTH,
  134.     &image_data_toggle_knob_selected[0], 0, 0, NULL
  135.    }, {        /* toggle select check unselected */
  136.     IMAGE_HORIZ_OFFSET, IMAGE_VERT_OFFSET, IMAGE_CHECK_WIDTH,
  137.     IMAGE_CHECK_HEIGHT, 0, NULL, 0, 0, NULL
  138.    }, {        /* toggle select check selected */
  139.     IMAGE_HORIZ_OFFSET, IMAGE_VERT_OFFSET, IMAGE_CHECK_WIDTH,
  140.     IMAGE_CHECK_HEIGHT, IMAGE_CHECK_DEPTH,
  141.     &image_data_toggle_check_selected[0], 0, 0, NULL
  142.    }, {        /* cycle */
  143.     0, 0, IMAGE_CYCLE_WIDTH, IMAGE_CYCLE_HEIGHT, IMAGE_CYCLE_DEPTH,
  144.     &image_data_cycle[0], 0, 0, NULL
  145.    }, {        /* left count */
  146.     0, 0, IMAGE_COUNT_WIDTH, IMAGE_COUNT_HEIGHT, IMAGE_COUNT_DEPTH,
  147.     &image_data_count_left[0], 0, 0, NULL
  148.    }, {        /* right count */
  149.     0, 0, IMAGE_COUNT_WIDTH, IMAGE_COUNT_HEIGHT, IMAGE_COUNT_DEPTH,
  150.     &image_data_count_right[0], 0, 0, NULL
  151.    }
  152. };
  153. STATIC struct TextAttr  topaz80_attr = { (STRPTR)"topaz.font", TOPAZ_EIGHTY,
  154.                            FS_NORMAL, FPF_ROMFONT };
  155.     /* Static prototypes */
  156.  
  157. SHORT calc_color_level(SHORT color);
  158. VOID  init_render_info_images(struct RenderInfo  *ri);
  159. UBYTE get_image_pixel_color(struct Image  *image, USHORT x, USHORT y);
  160. VOID  set_image_pixel_color(struct Image  *image, USHORT x, USHORT y,
  161.                                    UBYTE color);
  162. BOOL  create_avail_fonts(struct RenderInfo  *ri);
  163. VOID  free_avail_fonts(struct RenderInfo  *ri);
  164.  
  165.     /* Static pragmas */
  166.  
  167. #pragma regcall(calc_color_level(d0))
  168. #pragma regcall(init_render_info_images(a0))
  169. #pragma regcall(get_image_pixel_color(a0,d0,d1))
  170. #pragma regcall(set_image_pixel_color(a0,d0,d1,d2))
  171. #pragma regcall(create_avail_fonts(a0))
  172. #pragma regcall(free_avail_fonts(a0))
  173.  
  174.     /* Get render info for given screen */
  175.  
  176.    struct RenderInfo  *
  177. get_render_info(struct Screen  *screen, USHORT flags)
  178. {
  179.    struct RenderInfo  *ri;
  180.  
  181.    if (ri = AllocMem((LONG)sizeof(struct RenderInfo),
  182.                       (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
  183.       struct Screen  screen_data;
  184.       USHORT screen_type;
  185.  
  186.       /* Get screen data - if no screen given then use workbench screen */
  187.       if (!screen) {
  188.      LONG ilock;
  189.  
  190.      /* Get pointer to workbench screen */
  191.      ilock  = LockIBase(0L);
  192.      screen = IntuitionBase->FirstScreen;
  193.      while (screen && (screen->Flags & SCREENTYPE) != WBENCHSCREEN) {
  194.         screen = screen->NextScreen;
  195.      }
  196.      UnlockIBase(ilock);
  197.      screen_type = WBENCHSCREEN;
  198.       } else {
  199.      screen_type = CUSTOMSCREEN;
  200.       }
  201.       if (GetScreenData((BYTE *)&screen_data, (LONG)sizeof(struct Screen),
  202.                        (LONG)screen_type, screen) == TRUE) {
  203.      struct Image  *image;
  204.      USHORT *data;
  205.      ULONG  data_size;
  206.      SHORT  i;
  207.  
  208.      /* Get screen and window data */
  209.      ri->ri_Screen             = screen;
  210.      screen                    = &screen_data;
  211.      ri->ri_ScreenWidth        = screen->Width;
  212.      ri->ri_ScreenHeight       = screen->Height;
  213.      ri->ri_ScreenDepth        = screen->RastPort.BitMap->Depth;
  214.      ri->ri_WindowBorderTop    = screen->BarHeight -
  215.                        screen->BarVBorder + screen->WBorTop;
  216.      ri->ri_WindowBorderLeft   = screen->WBorLeft;
  217.      ri->ri_WindowBorderRight  = screen->WBorRight;
  218.      ri->ri_WindowBorderBottom = screen->WBorBottom;
  219.      ri->ri_Flags              = flags;
  220.      ri->ri_ID                 = ISUP_ID;
  221.  
  222.      /* Calc chipmem buffer size for image data */
  223.      for (i = 0, image = &images[0], data_size = 0;
  224.                       i < MAX_RENDER_IMAGES; i++, image++) {
  225.         if (image->ImageData) {
  226.            data_size += (image->Width / 16 + (image->Width & 15 ? 1 : 0))
  227.                    * image->Height * ri->ri_ScreenDepth * 2;
  228.         }
  229.      }
  230.      if (data = AllocMem(data_size,
  231.                   (LONG)MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR)) {
  232.         SHORT num_colors;
  233.  
  234.         /* Insert image data buffer and size */
  235.         ri->ri_ImageData     = data;
  236.         ri->ri_ImageDataSize = data_size;
  237.  
  238.         /* Calculate render colors */
  239.         if ((num_colors = 1 << ri->ri_ScreenDepth) > MAX_RENDER_COLORS) {
  240.            num_colors = MAX_RENDER_COLORS;
  241.         }
  242.         if (num_colors < 3) {
  243.  
  244.            /* Set render pens for monochrome screen */
  245.            if (flags & RENDER_INFO_FLAG_BACK_FILL) {
  246.           ri->ri_HighlightPen = 0;
  247.           ri->ri_ShadowPen    = 0;
  248.           ri->ri_TextPen1     = 0;
  249.           ri->ri_TextPen2     = 0;
  250.           ri->ri_BackPen      = 1;
  251.            } else {
  252.           ri->ri_HighlightPen = 1;
  253.           ri->ri_ShadowPen    = 1;
  254.           ri->ri_TextPen1     = 1;
  255.           ri->ri_TextPen2     = 1;
  256.           ri->ri_BackPen      = 0;
  257.            }
  258.         } else {
  259.            struct ColorMap  *cmap;
  260.            SHORT back_color, max_diff, colors[MAX_RENDER_COLORS],
  261.              color_levels[MAX_RENDER_COLORS],
  262.              pens[MAX_RENDER_COLORS];
  263.  
  264.            /* Get current screen colors */
  265.            Forbid();
  266.            for (i = 0, cmap = screen->ViewPort.ColorMap; i < num_colors;
  267.                                       i++) {
  268.           colors[i]       = GetRGB4(cmap, (LONG)i);
  269.           color_levels[i] = calc_color_level(colors[i]);
  270.           pens[i]         = i;
  271.            }
  272.            Permit();
  273.  
  274.            /* Save normal background color */
  275.            back_color = colors[0];
  276.  
  277.            /* Sort colors darkest to brightest (BUBBLE SORT) */
  278.            for (i = 0; i < (num_colors - 1); i++) {
  279.           SHORT j;
  280.  
  281.           for (j = i + 1; j < num_colors; j++) {
  282.              if (color_levels[i] > color_levels[j]) {
  283.             SHORT temp;
  284.  
  285.             /* Swap colors, color levels and pens */
  286.             temp      = colors[i];
  287.             colors[i] = colors[j];
  288.             colors[j] = temp;
  289.  
  290.             temp            = color_levels[i];
  291.             color_levels[i] = color_levels[j];
  292.             color_levels[j] = temp;
  293.  
  294.             temp    = pens[i];
  295.             pens[i] = pens[j];
  296.             pens[j] = temp;
  297.              }
  298.           }
  299.            }
  300.            if (flags & RENDER_INFO_FLAG_BACK_FILL) {
  301.  
  302.           /* Set render pens - highlight pen first */
  303.           ri->ri_HighlightPen = pens[num_colors - 1];   /* use brightest color */
  304.  
  305.           /* Set shadow pen */
  306.           ri->ri_ShadowPen = pens[0];   /* use darkest color */
  307.  
  308.           /* Set back pen */
  309.           i = 1;   /* use 2nd darkest color */
  310.           if (! pens[i]) {   /* don't use normal background color */
  311.              i++;
  312.           }
  313.           ri->ri_BackPen = pens[i];
  314.           back_color     = colors[i];   /* new background color */
  315.            } else {
  316.  
  317.           /* Set render pens - highlight pen first */
  318.           i = num_colors - 1;   /* use brightest color */
  319.           if (! pens[i]) {   /* don't use normal background color */
  320.              i--;
  321.           }
  322.           ri->ri_HighlightPen = pens[i];
  323.  
  324.           /* Set shadow pen */
  325.           i = 0;   /* use darkest color */
  326.           if (! pens[i]) {   /* don't use normal background color */
  327.              i++;
  328.           }
  329.           ri->ri_ShadowPen = pens[i];
  330.  
  331.           /* Set back pen */
  332.           ri->ri_BackPen = 0;
  333.            }
  334.  
  335.            /* Set text pen 1 - use color with greatest difference to
  336.         * back color */
  337.            for (i = 0, max_diff = 0; i < num_colors; i++) {
  338.           SHORT diff;
  339.  
  340.           if ((diff = calc_color_difference(colors[i],
  341.                           back_color)) > max_diff) {
  342.              max_diff        = diff;
  343.              ri->ri_TextPen1 = pens[i];
  344.           }
  345.            }
  346.  
  347.            /* Set text pen 2 - use color with greatest difference to
  348.         * back color and other color than highlight or shadow pen */
  349.            for (i = 0, max_diff = 0; i < num_colors; i++) {
  350.           SHORT diff;
  351.  
  352.           if ((diff = calc_color_difference(colors[i],
  353.                           back_color)) > max_diff) {
  354.              SHORT text1_pen = ri->ri_TextPen1, text2_pen = pens[i];
  355.  
  356.              /* Don't use text 1 pen again */
  357.              if (text2_pen != text1_pen) {
  358.  
  359.             /* Use special algorithm for 1 and 2 bitplanes */
  360.             if (num_colors < 5) {
  361.  
  362.                /* Try to get the pen not used for highlight and
  363.                 * shadow color if this isn't already used for
  364.                 * text 1 color */
  365.                if ((text1_pen != ri->ri_HighlightPen &&
  366.                        text1_pen != ri->ri_ShadowPen) ||
  367.                     (text2_pen != ri->ri_HighlightPen &&
  368.                        text2_pen != ri->ri_ShadowPen)) {
  369.                   max_diff        = diff;
  370.                   ri->ri_TextPen2 = pens[i];
  371.                }
  372.             } else {
  373.  
  374.                /* Try to get the best one from pens not used for
  375.                 * highlight and shadow color */
  376.                if (text2_pen != ri->ri_HighlightPen &&
  377.                         text2_pen != ri->ri_ShadowPen) {
  378.                   max_diff        = diff;
  379.                   ri->ri_TextPen2 = pens[i];
  380.                }
  381.             }
  382.              }
  383.           }
  384.            }
  385.             }
  386.  
  387.         /* Get font and attributes for rendering texts */
  388.         if (!(flags & RENDER_INFO_FLAG_AVAIL_FONTS) ||
  389.                        create_avail_fonts(ri) == TRUE) {
  390.            struct TextFont  *tf;
  391.  
  392.            /* First try to open screen font - if any */
  393.            Forbid();
  394.            if (!screen->Font) {
  395.           tf = NULL;
  396.            } else {
  397.           tf = open_font(ri, screen->Font);
  398.            }
  399.            Permit();
  400.            if (tf) {
  401.           struct TextAttr  *ta = &ri->ri_TextAttr;
  402.  
  403.           /* Build text attribute structure from screen font */
  404.           ta->ta_Name  = (STRPTR)tf->tf_Message.mn_Node.ln_Name;
  405.           ta->ta_YSize = tf->tf_YSize;
  406.           ta->ta_Style = tf->tf_Style;
  407.           ta->ta_Flags = tf->tf_Flags;
  408.            } else {
  409.  
  410.           /* Fall back to TOPAZ80 */
  411.           if (tf = open_font(ri, &topaz80_attr)) {
  412.              CopyMem((BYTE *)&topaz80_attr, (BYTE *)&ri->ri_TextAttr,
  413.                          (LONG)sizeof(struct TextAttr));
  414.           }
  415.            }
  416.            if (ri->ri_TextFont = tf) {
  417.           init_render_info_images(ri);
  418.           return(ri);
  419.            }
  420.            free_avail_fonts(ri);
  421.         }
  422.      }
  423.       }
  424.       FreeMem(ri, (LONG)sizeof(struct RenderInfo));
  425.    }
  426.    return(NULL);
  427. }
  428.     /* Free render info */
  429.  
  430.    VOID
  431. free_render_info(struct RenderInfo  *ri)
  432. {
  433.    if (ri && ri->ri_ID == ISUP_ID) {
  434.       if (ri->ri_TextFont) {
  435.      CloseFont(ri->ri_TextFont);
  436.       }
  437.       free_avail_fonts(ri);
  438.       FreeMem(ri->ri_ImageData, ri->ri_ImageDataSize);
  439.       FreeMem(ri, (LONG)sizeof(struct RenderInfo));
  440.    }
  441. }
  442.     /* Calc color level with specified scaling values */
  443.  
  444.    STATIC SHORT
  445. calc_color_level(SHORT color)
  446. {
  447.    return(calc_color_difference(color, 0));
  448. }
  449.     /* Calc color difference with specified scaling values */
  450.  
  451.    SHORT   /* non static - needed by menus.c too */
  452. calc_color_difference(SHORT color1, SHORT color2)
  453. {
  454.    USHORT temp, diff;
  455.  
  456.    temp  = (color1 & 0x00f) - (color2 & 0x00f);
  457.    diff  = temp * temp * BLUE_SCALE;
  458.    temp  = ((color1 >> 4) & 0x00f) - ((color2 >> 4) & 0x00f);
  459.    diff += temp * temp * GREEN_SCALE;
  460.    temp  = ((color1 >> 8) & 0x00f) - ((color2 >> 8) & 0x00f);
  461.    diff += temp * temp * RED_SCALE;
  462.    return(diff);
  463. }
  464.     /* Init render info images */
  465.  
  466.    STATIC VOID
  467. init_render_info_images(struct RenderInfo *ri)
  468. {
  469.    struct Image  *image_src = &images[0], *image_dest = &ri->ri_Images[0];
  470.    USHORT i, *data = ri->ri_ImageData;
  471.  
  472.    CopyMem((BYTE *)image_src, (BYTE *)image_dest,
  473.               (LONG)(MAX_RENDER_IMAGES * sizeof(struct Image)));
  474.    for (i = 0; i < MAX_RENDER_IMAGES; i++, image_src++, image_dest++) {
  475.  
  476.       /* Set image depth first - needed by pixel functions */
  477.       image_dest->Depth = ri->ri_ScreenDepth;
  478.  
  479.       /* Init image data if any */
  480.       if (image_src->ImageData) {
  481.      USHORT y, width = image_src->Width, height = image_src->Height,
  482.         depth = image_dest->Depth;   /* DEST image depth !!! */
  483.  
  484.      /* Set data buffer ptr */
  485.      image_dest->ImageData = data;
  486.      image_dest->PlanePick = (1 << depth) - 1;
  487.      data += (width / 16 + (width & 15 ? 1 : 0)) * height * depth;
  488.  
  489.      /* Convert image data to current colors */
  490.      for (y = 0; y < height; y++) {
  491.         USHORT x;
  492.  
  493.         for (x = 0; x < width; x++) {
  494.            UBYTE color;
  495.  
  496.            switch(get_image_pixel_color(image_src, x, y)) {
  497.           case 0 :   /* back pen */
  498.              color = ri->ri_BackPen;
  499.              break;
  500.  
  501.           case 1 :   /* highlight pen */
  502.              color = ri->ri_HighlightPen;
  503.              break;
  504.  
  505.           case 2 :   /* shadow pen */
  506.              color = ri->ri_ShadowPen;
  507.              break;
  508.  
  509.           default :   /* special pen */
  510.              color = ri->ri_TextPen2;
  511.              break;
  512.            }
  513.            set_image_pixel_color(image_dest, x, y, color);
  514.         }
  515.      }
  516.       } else {
  517.      UBYTE color;
  518.  
  519.      /* No image data -> monochrome rectangle */
  520.      switch(image_src->PlaneOnOff) {
  521.         case 0 :   /* back pen */
  522.            color = ri->ri_BackPen;
  523.            break;
  524.  
  525.         case 1 :   /* highlight pen */
  526.            color = ri->ri_HighlightPen;
  527.            break;
  528.  
  529.         case 2 :   /* shadow pen */
  530.            color = ri->ri_ShadowPen;
  531.            break;
  532.  
  533.         default :   /* special pen */
  534.            color = ri->ri_TextPen2;
  535.            break;
  536.      }
  537.      image_dest->PlaneOnOff = color;
  538.       }
  539.    }
  540. }
  541.     /* Get color of image pixel */
  542.  
  543.    STATIC UBYTE
  544. get_image_pixel_color(struct Image  *image, USHORT x, USHORT y)
  545. {
  546.    USHORT modulo = image->Width / 16 + (image->Width & 15 ? 1 : 0),
  547.       *data = image->ImageData + y * modulo + x / 16,
  548.       data_offset = image->Height * modulo,
  549.       bit_mask = 0x8000 >> (x & 15);
  550.    UBYTE  i, depth = image->Depth, color_mask = 1, color = 0;
  551.  
  552.    for (i = 0; i < depth; i++, data += data_offset, color_mask <<= 1) {
  553.       if (*data & bit_mask) {
  554.      color |= color_mask;
  555.       }
  556.    }
  557.    return(color);
  558. }
  559.     /* Set color of image pixel */
  560.  
  561.    STATIC VOID
  562. set_image_pixel_color(struct Image  *image, USHORT x, USHORT y, UBYTE color)
  563. {
  564.    USHORT modulo = image->Width / 16 + (image->Width & 15 ? 1 : 0),
  565.       *data = image->ImageData + y * modulo + x / 16,
  566.       data_offset = image->Height * modulo,
  567.       bit_mask = 0x8000 >> (x & 15);
  568.    UBYTE  i, depth = image->Depth;
  569.  
  570.    for (i = 0; i < depth; i++, data += data_offset, color >>= 1) {
  571.       if (color & 1) {
  572.      *data |= bit_mask;
  573.       }
  574.    }
  575. }
  576.     /* Open window */
  577.  
  578.    struct Window *
  579. open_window(struct RenderInfo  *ri, struct NewWindow  *org_nw, USHORT flags)
  580. {
  581.    struct Window  *win = NULL;
  582.  
  583.    if (ri && ri->ri_ID == ISUP_ID && org_nw) {
  584.       struct NewWindow  new_nw = *org_nw, *nw = &new_nw;
  585.       SHORT  left_edge = nw->LeftEdge, top_edge = nw->TopEdge;
  586.       USHORT width = nw->Width, height = nw->Height,
  587.          max_width = ri->ri_ScreenWidth, max_height = ri->ri_ScreenHeight;
  588.  
  589.       /* Scale new window dimension */
  590.       if (width > max_width) {
  591.      width     = max_width;
  592.      left_edge = 0;
  593.       } else {
  594.      if ((left_edge + width) > max_width) {
  595.         left_edge = max_width - width;
  596.      }
  597.       }
  598.       if (height > max_height) {
  599.      height   = max_height;
  600.      top_edge = 0;
  601.       } else {
  602.      if ((top_edge + height) > max_height) {
  603.         top_edge = max_height - height;
  604.      }
  605.       }
  606.  
  607.       /* Change new window struct */
  608.       if (flags & OPEN_WINDOW_FLAG_RENDER_PENS) {
  609.  
  610.      /* Set colors */
  611.      if (ri->ri_Flags & RENDER_INFO_FLAG_BACK_FILL) {
  612.         nw->DetailPen = ri->ri_TextPen1;
  613.         nw->BlockPen  = ri->ri_BackPen;
  614.      } else {
  615.         nw->DetailPen = ri->ri_BackPen;
  616.         nw->BlockPen  = ri->ri_TextPen1;
  617.      }
  618.       }
  619.       if (!(flags & OPEN_WINDOW_FLAG_NO_INNER_WINDOW) &&
  620.                (ri->ri_Flags & RENDER_INFO_FLAG_INNER_WINDOW)) {
  621.      USHORT hoffset = ri->ri_WindowBorderLeft,
  622.         voffset = ri->ri_WindowBorderTop;
  623.  
  624.      /* Change width and left edge for inner window dimension */
  625.      if ((width += hoffset + ri->ri_WindowBorderRight) > max_width) {
  626.         width     = max_width;
  627.         left_edge = 0;
  628.      } else {
  629.         if (left_edge > hoffset) {
  630.            left_edge -= hoffset;
  631.            if ((left_edge + width) > max_width) {
  632.           left_edge = max_width - width;
  633.            }
  634.         } else {
  635.            left_edge = 0;
  636.         }
  637.      }
  638.  
  639.      /* Change height and top edge for inner window dimension */
  640.      if ((height += voffset + ri->ri_WindowBorderBottom) > max_height) {
  641.         height   = max_height;
  642.         top_edge = 0;
  643.      } else {
  644.         if (top_edge > voffset) {
  645.            top_edge -= voffset;
  646.            if ((top_edge + height) > max_height) {
  647.           top_edge = max_height - height;
  648.            }
  649.         } else {
  650.            top_edge = 0;
  651.         }
  652.      }
  653.       }
  654.  
  655.       /* Center window AFTER calculation of inner window dimension */
  656.       if (flags & OPEN_WINDOW_FLAG_CENTER_SCREEN) {
  657.  
  658.      /* Center window on screen */
  659.      left_edge = (max_width - width) / 2;
  660.      top_edge  = (max_height - height) / 2;
  661.       } else {
  662.      if (flags & OPEN_WINDOW_FLAG_CENTER_MOUSE) {
  663.  
  664.         /* Center window over current position of mouse pointer */
  665.         left_edge = ri->ri_Screen->MouseX - width / 2;
  666.         top_edge  = ri->ri_Screen->MouseY - height / 2;
  667.  
  668.         /* Scale window position according to screen dimension */
  669.         if (left_edge < 0) {
  670.            left_edge = 0;
  671.         } else {
  672.            if (left_edge > (max_width - width)) {
  673.           left_edge = max_width - width;
  674.            }
  675.         }
  676.         if (top_edge < 0) {
  677.            top_edge = 0;
  678.         } else {
  679.            if (top_edge > (max_height - height)) {
  680.           top_edge = max_height - height;
  681.            }
  682.         }
  683.      }
  684.       }
  685.  
  686.       /* Insert position + dimension of window and try to open it */
  687.       nw->LeftEdge = left_edge;
  688.       nw->TopEdge  = top_edge;
  689.       nw->Width    = width;
  690.       nw->Height   = height;
  691.       if (win = OpenWindow(nw)) {
  692.  
  693.      /* Finally fill window background */
  694.      if (ri->ri_Flags & RENDER_INFO_FLAG_BACK_FILL) {
  695.         clear_window(ri, win, 0, 0, width, height, 0);
  696.      }
  697.       }
  698.    }
  699.    return(win);
  700. }
  701.     /* Clear given rectangle of window with data from render info */
  702.  
  703.    VOID
  704. clear_window(struct RenderInfo  *ri, struct Window  *win, USHORT left_edge,
  705.          USHORT top_edge, USHORT width, USHORT height, USHORT flags)
  706. {
  707.    if (ri && ri->ri_ID == ISUP_ID && win) {
  708.       USHORT inner_left, inner_top, inner_width, inner_height,
  709.          ri_flags = ri->ri_Flags;
  710.  
  711.       /* Calc inner window dimension */
  712.       if ((ri_flags & RENDER_INFO_FLAG_INNER_WINDOW) ||
  713.                   (ri_flags & RENDER_INFO_FLAG_BACK_FILL)) {
  714.      inner_left   = ri->ri_WindowBorderLeft;
  715.      inner_top    = ri->ri_WindowBorderTop;
  716.      inner_width  = win->Width - inner_left - ri->ri_WindowBorderRight;
  717.      inner_height = win->Height - inner_top - ri->ri_WindowBorderBottom;
  718.       } else {
  719.      inner_left   = 0;
  720.      inner_top    = 0;
  721.      inner_width  = win->Width;
  722.      inner_height = win->Height;
  723.       }
  724.  
  725.       /* Check if given rectangle fits into inner window */
  726.       if ((SHORT)left_edge >= 0 && (SHORT)top_edge >= 0 && width &&
  727.              height && left_edge < (inner_left + inner_width) &&
  728.                     top_edge < (inner_top + inner_height)) {
  729.      struct RastPort  *rp = win->RPort;
  730.  
  731.      /* Add offsets for inner window to given upper left position */
  732.      if (!(flags & CLEAR_WINDOW_FLAG_ABSOLUTE_POS)) {
  733.         left_edge += inner_left;
  734.         top_edge  += inner_top;
  735.  
  736.         /* Scale upper left position of given rectangle if neccessary */
  737.         if (left_edge < inner_left) {
  738.            left_edge = inner_left;
  739.         }
  740.         if (top_edge < inner_top) {
  741.            top_edge = inner_top;
  742.         }
  743.      }
  744.  
  745.      /* Scale dimension of given rectangle if neccessary */
  746.      if ((SHORT)width <= 0 || (left_edge + width) > (inner_left +
  747.                                  inner_width)) {
  748.         width = inner_left + inner_width - left_edge;
  749.      }
  750.      if ((SHORT)height <= 0 || (top_edge + height) > (inner_top +
  751.                                 inner_height)) {
  752.         height = inner_top + inner_height - top_edge;
  753.      }
  754.  
  755.      /* Set draw mode, colors and fill pattern for using raster */
  756.      if (flags & CLEAR_WINDOW_FLAG_USE_RASTER) {
  757.         STATIC USHORT raster_pattern[] = { 0xaaaa, 0x5555 };
  758.  
  759.         SetDrMd(rp, (LONG)JAM2);
  760.         SetAPen(rp, (LONG)ri->ri_HighlightPen);
  761.         SetBPen(rp, (LONG)ri->ri_BackPen);
  762.         SetAfPt(rp, &raster_pattern[0], 1L);   /* macro !!! */
  763.      } else {
  764.  
  765.         /* Set draw mode */
  766.         if (!(flags & CLEAR_WINDOW_FLAG_CUSTOM_DRAW_MODE)) {
  767.            SetDrMd(rp, (LONG)JAM1);
  768.         }
  769.  
  770.         /* Set fill colors */
  771.         if (!(flags & CLEAR_WINDOW_FLAG_CUSTOM_COLOR)) {
  772.            USHORT apen;
  773.  
  774.            /* Check if special color needed */
  775.            if (flags & CLEAR_WINDOW_FLAG_TEXT1_COLOR) {
  776.           apen = ri->ri_TextPen1;
  777.            } else {
  778.           if (flags & CLEAR_WINDOW_FLAG_TEXT2_COLOR) {
  779.              apen = ri->ri_TextPen2;
  780.           } else {
  781.  
  782.              /* Use background color */
  783.              if ((ri_flags & RENDER_INFO_FLAG_BACK_FILL) &&
  784.                 !(flags & CLEAR_WINDOW_FLAG_NORMAL_COLOR)) {
  785.             apen = ri->ri_BackPen;
  786.              } else {
  787.             apen = 0;
  788.              }
  789.           }
  790.            }
  791.            SetAPen(rp, (LONG)apen);
  792.         }
  793.      }
  794.  
  795.      /* And do clearing window background */
  796.      RectFill(rp, (LONG)left_edge, (LONG)top_edge, (LONG)(left_edge +
  797.                  width - 1), (LONG)(top_edge + height - 1));
  798.  
  799.      /* Clear fill pattern */
  800.      if (flags & CLEAR_WINDOW_FLAG_USE_RASTER) {
  801.         SetAfPt(rp, NULL, 1L);   /* macro !!! */
  802.      }
  803.       }
  804.    }
  805. }
  806.     /* Close window safely, even if shared user port */
  807.  
  808.    VOID
  809. close_window(struct Window  *win, BOOL more_windows)
  810. {
  811.    if (win) {
  812.  
  813.       /* Check if any IDCMP flag used */
  814.       if (win->UserPort) {
  815.      struct IntuiMessage  *msg, *succ;
  816.  
  817.      /* Reply all messages for given window */
  818.      Forbid();
  819.      msg = (struct IntuiMessage *)win->UserPort->mp_MsgList.lh_Head;
  820.      while (succ = (struct IntuiMessage *)
  821.                      msg->ExecMessage.mn_Node.ln_Succ) {
  822.         if (more_windows == FALSE || msg->IDCMPWindow == win) {
  823.            Remove((struct Node *)msg);
  824.            ReplyMsg((struct Message *)msg);
  825.         }
  826.         msg = succ;
  827.      }
  828.  
  829.      /* Don't close shared user port */
  830.      if (more_windows == TRUE) {
  831.         win->UserPort = NULL;
  832.         ModifyIDCMP(win, 0L);
  833.      }
  834.      Permit();
  835.       }
  836.       CloseWindow(win);
  837.    }
  838. }
  839.     /* Create list of available fonts - called by create_render_info() */
  840.  
  841.    STATIC BOOL
  842. create_avail_fonts(struct RenderInfo  *ri)
  843. {
  844.    struct AvailFontsHeader  *afh;
  845.    LONG size = DEFAULT_AVAIL_FONTS_BUFFER_SIZE;
  846.    BOOL success = FALSE;
  847.  
  848.    /* Allocate buffer and fill it with data from available fonts */
  849.    if (afh = AllocMem(size, (LONG)MEMF_PUBLIC)) {
  850.       LONG new_size;
  851.  
  852.       if (new_size = AvailFonts((BYTE *)afh, size,
  853.                          (LONG)AFF_MEMORY | AFF_DISK)) {
  854.      /* Allocate larger buffer and try again */
  855.      FreeMem(afh, size);
  856.      size += new_size;
  857.      if (afh = AllocMem(size, (LONG)MEMF_PUBLIC)) {
  858.         AvailFonts((BYTE *)afh, size, (LONG)AFF_MEMORY | AFF_DISK);
  859.      }
  860.       }
  861.  
  862.       /* Save font header in render info data structure */
  863.       ri->ri_AvailFontsHeader     = afh;
  864.       ri->ri_AvailFontsHeaderSize = size;
  865.       success = TRUE;
  866.    }
  867.    return(success);
  868. }
  869.     /* Free list of available fonts - called by free_render_info() */
  870.  
  871.    STATIC VOID
  872. free_avail_fonts(struct RenderInfo  *ri)
  873. {
  874.    if (ri->ri_AvailFontsHeader && ri->ri_AvailFontsHeaderSize) {
  875.       FreeMem(ri->ri_AvailFontsHeader, ri->ri_AvailFontsHeaderSize);
  876.    }
  877. }
  878.     /* Return ptr to list of available fonts */
  879.  
  880.    struct AvailFontsHeader *
  881. avail_fonts(struct RenderInfo  *ri)
  882. {
  883.    struct AvailFontsHeader  *afh = NULL;
  884.  
  885.    if (ri && ri->ri_ID == ISUP_ID &&
  886.                 (ri->ri_Flags & RENDER_INFO_FLAG_AVAIL_FONTS)) {
  887.       afh = ri->ri_AvailFontsHeader;
  888.    }
  889.    return(afh);
  890. }
  891.     /* Check if given font is available and return its correct data */
  892.  
  893.    struct TextAttr *
  894. ask_font(struct RenderInfo  *ri, struct TextAttr  *ta)
  895. {
  896.    struct TextAttr  *best_ta = NULL;
  897.  
  898.    if (ri && ri->ri_ID == ISUP_ID && ta) {
  899.       if (!(ri->ri_Flags & RENDER_INFO_FLAG_AVAIL_FONTS)) {
  900.      best_ta = ta;
  901.       } else {
  902.      struct AvailFontsHeader  *afh = ri->ri_AvailFontsHeader;
  903.      USHORT num = afh->afh_NumEntries;
  904.  
  905.      if (num) {
  906.         struct AvailFonts  *af = (struct AvailFonts *)(afh + 1);
  907.         USHORT search_ysize = ta->ta_YSize, best_ysize = 0;
  908.  
  909.         do {
  910.            struct TextAttr  *avail_ta = &af++->af_Attr;
  911.            int stricmp(const char *_s1, const char *_s2);   /* manually prototyping non ANSI function */
  912.  
  913.            if (!stricmp((BYTE *)avail_ta->ta_Name, (BYTE *)ta->ta_Name)) {
  914.           USHORT avail_ysize = avail_ta->ta_YSize;
  915.  
  916.           if (avail_ysize == search_ysize) {
  917.              best_ta = avail_ta;
  918.              break;
  919.           } else {
  920.              if (avail_ysize < search_ysize) {
  921.             if (avail_ysize > best_ysize) {
  922.                best_ysize = avail_ysize;
  923.                best_ta    = avail_ta;
  924.             }
  925.              } else {
  926.             if (!best_ysize || avail_ysize < best_ysize) {
  927.                best_ysize = avail_ysize;
  928.                best_ta    = avail_ta;
  929.             }
  930.              }
  931.           }
  932.            }
  933.         } while (--num);
  934.      }
  935.       }
  936.    }
  937.    return(best_ta);
  938. }
  939.     /* Open best available text font */
  940.  
  941.    struct TextFont *
  942. open_font(struct RenderInfo  *ri, struct TextAttr  *ta)
  943. {
  944.    struct TextFont  *tf = NULL;
  945.  
  946.    if (ri && ri->ri_ID == ISUP_ID && ta) {
  947.       if (ta = ask_font(ri, ta)) {
  948.      if (!(tf = OpenFont(ta)) || tf->tf_YSize != ta->ta_YSize) {
  949.         if (tf) {
  950.            CloseFont(tf);
  951.         }
  952.         tf = OpenDiskFont(ta);
  953.      }
  954.       }
  955.    }
  956.    return(tf);
  957. }
  958.